<template>
  <div class="container">
    <div class="app-container">
      <!-- 角色管理内容 -->
      <div class="role-operate">
        <!-- 按钮组件 -->
        <el-button
          type="primary"
          icon="el-icon-circle-plus"
          @click="showDialog = true"
          v-permission="'add:role'"
          >添加角色</el-button
        >
        <!-- 表格组件 -->
        <el-table :data="roleList" border stripe style="width: 100%" v-loading="loading">
          <!-- 放置列 -->
          <el-table-column
            align="center"
            width="200"
            prop="roleName"
            label="角色名称"
          >
            <!-- 利用 v-slot插槽获取当前行的数据 -->
            <template v-slot="{ row }">
              <el-input
                v-if="row.isEdit"
                v-model="row.editRow.roleName"
              ></el-input>
              <span v-else>{{ row.roleName }}</span>
            </template>
          </el-table-column>
          <el-table-column
            align="center"
            width="200"
            prop="roleKey"
            label="角色编码"
          >
            <!-- 利用 v-slot插槽获取当前行的数据 -->
            <template v-slot="{ row }">
              <!-- row.isEdit=true 如果是编辑状态下 是input输入框显示 -->
              <el-input
                v-if="row.isEdit"
                v-model="row.editRow.roleKey"
              ></el-input>
              <!-- 否则是span显示 -->
              <span v-else>{{ row.roleKey }}</span>
            </template>
          </el-table-column>

          <el-table-column align="center" width="200" label="是否启用">
            <!-- 自定义插槽滑块开关 插槽-->
            <!-- <template v-slot="{row}">
            <span>{{ row.status === 0 ? '启用' : '禁用'}}</span>
          </template> -->
            <template v-slot="{ row }">
              <!-- row.isEdit=true 如果是编辑状态下 是switch滑块显示 -->
              <template v-if="row.isEdit">
                <el-switch
                  v-model="row.editRow.status"
                  active-color="#13ce66"
                  inactive-color="#ff4949"
                  :active-value="false"
                  :inactive-value="true"
                  @change="changeEditStatus(row)"
                >
                </el-switch>
              </template>
              <template v-else>
                <el-switch
                  v-model="row.status"
                  active-color="#13ce66"
                  inactive-color="#ff4949"
                  :active-value="false"
                  :inactive-value="true"
                  @change="changeStatus(row)"
                >
                </el-switch>
              </template>
            </template>
          </el-table-column>

          <el-table-column align="center" prop="remark" label="备注">
            <!-- 利用 v-slot插槽获取当前行的数据 -->
            <template v-slot="{ row }">
              <el-input
                v-if="row.isEdit"
                type="textarea"
                v-model="row.editRow.remark"
              ></el-input>
              <span v-else>{{ row.remark }}</span>
            </template>
          </el-table-column>
          <el-table-column align="center" label="操作">
            <template v-slot="{ row }">
              <!-- 编辑状态下，显示确定和取消按钮 -->
              <template v-if="row.isEdit">
                <el-button type="primary" size="medium" @click="btnEditOk(row)"
                  >确定</el-button
                >
                <el-button size="medium" @click="btnEditCancel(row)"
                  >取消</el-button
                >
              </template>
              <!-- 非编辑状态正常显示 -->
              <template v-else>
                <!-- 自定义插槽 -->
                <el-button
                  type="primary"
                  size="medium"
                  @click="btnPermisson(row)"
                  >分配权限</el-button
                >
                <!-- 行内编辑第二步，给按钮绑定一个方法 -->
                <el-button type="warning" size="medium" @click="btnEditRow(row)"
                  >编辑</el-button
                >
                <!-- popconfirm 气泡确认框组件 -->
                <el-popconfirm
                  confirm-button-text="好的"
                  cancel-button-text="不用了"
                  icon="el-icon-info"
                  icon-color="red"
                  title="这是一段内容确定删除吗？"
                  @onConfirm="btnDelete(row.roleId)"
                >
                  >
                  <el-button
                    slot="reference"
                    type="danger"
                    size="medium"
                    icon="el-icon-delete"
                    style="margin-left: 10px"
                    v-permission="'del:role'"
                    >删除</el-button
                  >
                </el-popconfirm>
              </template>
            </template>
          </el-table-column>
        </el-table>
        <!-- 放置分页组件 -->
        <el-row
          type="flex"
          justify="center"
          align="middle"
          style="height: 60px"
        >
          <el-pagination
            layout="total,prev, pager, next"
            :total="total"
            :page-size="pageSize"
            :current-page="page"
            @current-change="changePage"
          >
            >
          </el-pagination>
        </el-row>
      </div>
    </div>

    <!-- 弹层组件 dialog -->
    <el-dialog
      title="新增角色"
      :visible.sync="showDialog"
      width="40%"
      @close="btnCancel"
    >
      <el-form
        label-width="120"
        :model="roleForm"
        :rules="rules"
        ref="roleForm"
      >
        <!-- prop="roleName" 对应的是我们rules{}对象中的字段 -->
        <el-form-item label="角色名称" prop="roleName">
          <el-input v-model="roleForm.roleName"></el-input>
        </el-form-item>
        <el-form-item label="角色编码" prop="roleKey">
          <el-input v-model="roleForm.roleKey"></el-input>
        </el-form-item>
        <!-- 如果不需要校验，那么就不需要写prop属性 ,但是如果使用element-table时候，需要重置表单，那么这个必须设置prop这个属性，不然重置不生效 -->
        <el-form-item label="是否启用" prop="status">
          <el-switch
            v-model="roleForm.status"
            active-color="#13ce66"
            inactive-color="#ff4949"
            :active-value="false"
            :inactive-value="true"
          >
          </el-switch>
        </el-form-item>
        <el-form-item label="备注" prop="remark">
          <el-input type="textarea" v-model="roleForm.remark"></el-input>
        </el-form-item>
        <el-form-item>
          <el-row type="flex" justify="center">
            <el-col :span="12">
              <el-button type="primary" @click="btnOk">确 定</el-button>
              <el-button @click="btnCancel">取 消</el-button>
            </el-col>
          </el-row>
        </el-form-item>
      </el-form>
    </el-dialog>

    <!-- 放一个权限的弹层 show-checkbox='true' 显示复选框 node-key="menuId"绑的数据id-->
    <el-dialog title="分配权限" :visible.sync="showPermDialog" width="40%">
      <el-tree
        :data="permissionData"
        show-checkbox
        node-key="menuId"
        :props="defaultProps"
        check-strictly
        ref="permTree"
        default-expand-all
        :default-checked-keys="permIds"
      >
      </el-tree>
      <el-row type="flex" justify="center" slot="footer">
        <el-col :span="12">
          <el-button type="primary" @click="btnPermOk">确 定</el-button>
          <el-button @click="btnPermCancel">取 消</el-button>
        </el-col>
      </el-row>
    </el-dialog>
  </div>
</template>
<script>
import roleApi from "@/api/role";
import permissionApi from "@/api/permission";
import { permissionToTree } from "@/utils/index";

export default {
  name: "Role",
  data() {
    return {
      loading: true, //表格loading效果，默认为false
      //列表数据
      roleList: [],
      page: 1, //当前页码
      pageSize: 10, //每页条数
      total: 0, //总条数
      showDialog: false, //控制对话框显示与隐藏
      //角色的表单对象
      roleForm: {
        roleName: "",
        roleKey: "",
        status: false, //默认是启用状态 false(0):启用  true(1):禁用
        remark: "",
      },
      //校验规则
      rules: {
        roleName: [
          { required: true, message: "角色名称不能为空", trigger: "blur" },
        ],
        roleKey: [
          { required: true, message: "角色编码不能为空", trigger: "blur" },
        ],
      },

      showPermDialog: false, //是否显示权限弹窗
      permissionData: [], //权限数据
      defaultProps: {
        children: "children",
        label: "menuName",
      },
      currentRoleId: null, //记录当前角色id
      permIds: [], //记录当前角色拥有的权限id
    };
  },
  // 初始化调用
  created() {
    this.getRoleList();
  },
  methods: {
    async getRoleList() {
      this.loading = true;
      const result = await roleApi.getRoleList(this.page, this.pageSize);

      this.loading = false;
      this.roleList = result.records; //当前页的数据
      //获取返回的总条数
      this.total = result.total;

      this.roleList.forEach((item) => {
        //行内编辑第一步：在获取完成数据之后，在每一行添加一个标记
        //自己添加的动态属性isEdit是不具备动态响应的效果的
        //我们需要使用vue提供的this.$set()目标对象动态添加响应式数据
        // this.$set(目标对象,属性名称,初始值)
        this.$set(item, "isEdit", false); //给每一行添加一个标记
        // item.isEdit = false  这样是错误的添加，没有视图更新的效果

        //缓存每一行数据，用于点击点击编辑按钮的时候，回显数据
        this.$set(item, "editRow", {
          roleId: item.roleId,
          roleName: item.roleName,
          roleKey: item.roleKey,
          status: item.status,
          remark: item.remark,
        });
      });
    },

    //当页码发生变化时触发的函数
    changePage(nowPage) {
      this.page = nowPage;
      //调用methods中的函数,这个函数会重新发送axios获取新的分页数据
      this.getRoleList();
    },
    //当滑块状态发生变化时触发的函数
    async changeStatus(row) {
      //保持编辑状态的行数据不变
      // row.status = row.editRow.status
      // console.log("滑块状态发生变化");
      //console.log(row);//这里有当前行的所有数据
      //console.log(row.status); //当前行的状态
      //调用接口，发送请求，修改状态
      await roleApi.updateRoleStatus(row.roleId, row.status);
      this.$message.success("修改角色状态成功");
      //console.log(row);
    },
    //编辑状态下的跟新
    async changeEditStatus(row) {
      //保持编辑状态的行数据不变
      // row.status = row.editRow.status
      //调用接口，发送请求，修改状态
      await roleApi.updateRoleStatus(row.editRow.roleId, row.editRow.status);
      this.$message.success("修改角色状态成功");
      //更新外层的status状态，因为此时并没有请求接口，所以row.status和我们编辑的row.editRow.status不一样
      row.status = row.editRow.status;
    },
    //新增角色，确定按钮函数
    btnOk() {
      //先要保证表单校验先通过
      this.$refs.roleForm.validate(async (isOk) => {
        if (isOk) {
          await roleApi.addRole(this.roleForm);
          this.$message.success("新增角色成功");
          // //关闭对话框
          // this.showDialog = false;
          // //重置表单
          // this.$refs.roleForm.resetFields();
          //上面俩个操作我们封装到了取消按钮的函数中
          this.btnCancel();
          //重新获取最新的数据
          this.getRoleList();
        }
      });
    },

    //新增角色，取消按钮
    btnCancel() {
      //关闭对话框
      this.showDialog = false;
      //重置表单数据
      this.$refs.roleForm.resetFields();
    },

    //点击编辑  将外部的数据赋值给内部的表单
    btnEditRow(row) {
      // console.log(row); 当前行的数据
      row.isEdit = true; //改变编辑行的状态
      //更新缓存数据,已列表数据为准，防止你在编辑模式下，取消按钮之后，再次点开编辑是，数据不是最新的列表数据，而是上次已经取消的缓存数据
      row.editRow.roleName = row.roleName;
      row.editRow.roleKey = row.roleKey;
      row.editRow.status = row.status;
      row.editRow.remark = row.remark;
      //console.log(row.status);
    },

    //行内编辑，确定按钮方法
    async btnEditOk(row) {
      //角色名和角色code不为空
      if (row.editRow.roleName && row.editRow.roleKey) {
        //也可以这么写await roleApi.updateRole({...row.editRow,roleId:row.roleId})
        await roleApi.updateRole(row.editRow);
        this.$message.success("修改角色信息成功");
        // row.isEdit = false //改变编辑行的状态

        //更新外层row里面的列表中显示的数据，因为此时外层并没有请求最新的数据 status字段其实可以不用跟新
        // Object.assign(需要更新的对象,来源的数据)
        Object.assign(row, {
          ...row.editRow,
          isEdit: false, //退出编辑模式
        });
      } else {
        this.$message.warning("角色名称和角色编码不能为空!");
      }
    },

    //行内编辑，取消按钮的方法
    btnEditCancel(row) {
      row.isEdit = false; //取消编辑模式
    },

    //删除角色
    async btnDelete(roleId) {
      await roleApi.deleteRole(roleId);
      this.$message.success("删除角色成功");
      //重新获取最新的数据
      this.getRoleList();
    },

    // 分配权限按钮
    async btnPermisson(row) {
      //每次给个新的数据，往里面添加，覆盖上一次的数组中的数据
      this.permIds =[]
      //记录角色的roleId,因为分配权限的时候，需要根据角色id来分配权限
      this.currentRoleId = row.roleId;
      // 得到所有的权限
      const result = await permissionApi.getPermissionList();
      //把获取到的数据转为树形结构
      const treeList = permissionToTree(result, 0);
      //console.log(treeList);
      this.permissionData = treeList;
      // 得到当前角色所拥有的权限
      const data = await roleApi.findByRoleIdPermission(this.currentRoleId);
      // console.log(data);
      
      let currentMenuIds = [];
      if (data !== null && Array.isArray(data)) {
        // console.log(true);
        //把当前角色所拥有的权限id转为数组
        data.forEach((item) => {
          currentMenuIds.push(item.menuId)
        });
      } 
      //console.log(currentPermIds);
      this.permIds = currentMenuIds;
      //console.log(this.permIds);
      //显示分配权限对话框
      this.showPermDialog = true;
    },
    // 分配角色权限----确认按钮
    async btnPermOk() {
      // getCheckedKeys()是element-ui树形控件的方法，获取当前选中状态的所有的节点
      // console.log(this.$refs.permTree.getCheckedKeys());
      this.permIds = this.$refs.permTree.getCheckedKeys()
      console.log(this.permIds);
      //console.log("a",this.permIds);
      //而此时的this.permIds 只是上次选中的权限id，所以需要把上次选中的权限id和这次选中的权限id合并
      // this.permIds = [...this.permIds,...a]
      
      //根据当前角色id，分配权限
      await roleApi.addRolePermission(this.currentRoleId, this.permIds);
      this.$message.success("分配权限成功");
      //关闭对话框
      this.btnPermCancel()
    },
    // 分配角色权限----取消按钮
    btnPermCancel() {
      this.showPermDialog = false;
    },
  },
};
</script>

<style scoped>
.role-operate {
  padding: 10px;
}
</style>
